package com.xpec.c4.game.login;

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map.Entry;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.ms.service.module.account.message.SSessionCloseNotify;
import com.xpec.c4.game.time.TimeConstants;
import com.xpec.c4.game.utility.GUID;
import com.xpec.c4.game.utility.GameUtility;
import com.xpec.c4.service.common.EncryptHandler;

/**
 * 玩家帳號重新直接連線管理器
 * @author Wilson_Wu
 *
 */
public class ReconnectionManager {
	/** log4j object */
	private static final Log log = LogFactory.getLog(ReconnectionManager.class);

	private static String key = "C4@afK";

	/**
	 * 超過30分鐘沒有更新的就過期了
	 */
	public static final long EXPIRE_PERIOD = TimeConstants.MILLI_SECOND_PRE_MINUTE * 30;
	
	/**
	 * account 對應
	 * key - reconnectToken , value - 登入認證碼
	 */
	private HashMap<GUID , HashMap<String,LastLoginInfo>> accountLoginRecordMap = new HashMap<GUID , HashMap<String,LastLoginInfo>>();
	
	/**
	 * password to account
	 */
	private HashMap<String , GUID > lastCodeToAccountMap = new HashMap<String , GUID>();
	
	/**
	 * session id to LastLoginInfo
	 */
	private HashMap<GUID, LastLoginInfo> sessionToLastLoginInfoMap = new HashMap<GUID, LastLoginInfo>();
	
	/**
	 * loginmodule 多久檢查一次
	 */
	public  static long MODULE_CHECK_PERIOD = TimeConstants.MILLI_SECOND_PRE_HOUR * 1;
	
	/**
	 * 過期檢查
	 */
	public void expireCheck(){
		Iterator<Entry<GUID , HashMap<String,LastLoginInfo>>> itr = accountLoginRecordMap.entrySet().iterator();
		long ct = System.currentTimeMillis();
		while(itr.hasNext()){
			Entry<GUID , HashMap<String,LastLoginInfo>> node = itr.next();
			HashMap<String,LastLoginInfo> lastLoginInfoMap = node.getValue();

			//此帳號身上每個token時間檢查
			Iterator<Entry<String,LastLoginInfo>> nodeItr = lastLoginInfoMap.entrySet().iterator();
			while(nodeItr.hasNext()){
				Entry<String,LastLoginInfo> lastnode = nodeItr.next();
				LastLoginInfo loginInfo = lastnode.getValue();
				
				if (loginInfo == null) {
					nodeItr.remove();
				}
				
				//過期了刪掉
				if (loginInfo.lastOfflineTime >= 0 && (ct > (EXPIRE_PERIOD + loginInfo.lastOfflineTime))) {
					// 將 gateway code 對應 account id 的資料刪除
					lastCodeToAccountMap.remove(loginInfo.verifyCode);
					
					nodeItr.remove();
				}
			}
			
			//帳號已無token刪除
			if(GameUtility.getMapSize(lastLoginInfoMap) == 0){
				itr.remove();
			}
		}

		if (log.isInfoEnabled()) {
			log.info("after ReconnectionManager expireCheck()");
			log.info("accountLoginRecordMap.size = " + accountLoginRecordMap.size());
			log.info("lastCodeToAccountMap.size = " + lastCodeToAccountMap.size());
			log.info("sessionToLastLoginInfoMap.size = " + sessionToLastLoginInfoMap.size());
		}
	}
	/**
	 * 取得認證碼
	 * @param accountId
	 * @return
	 */
	public GUID verifyReconnectLoginInfo(String logincheckToken, String passwardCode){
		if(logincheckToken == null ||
		   passwardCode == null || 
		   !lastCodeToAccountMap.containsKey(passwardCode))
			return null;
		GUID accountId = lastCodeToAccountMap.get(passwardCode);
		if(accountId == null) return null;
		
		HashMap<String,LastLoginInfo> infos  = accountLoginRecordMap.get(accountId);
		if(infos == null) return null;

		LastLoginInfo info = infos.get(logincheckToken);
		if (info == null) {
			return null;
		}

		if(logincheckToken.equals(info.lastRandomToken))
			return accountId;
		else
			return null;
	}
	private String getVerifyCode(String lastRandomToken , GUID lastLoginPlayerGuid){
		return EncryptHandler.md5(lastRandomToken + lastLoginPlayerGuid + key);
	}
	
	public boolean updateAccountLastLoginPlayerGuid(GUID accountId, GUID lastLoginPlayerGuid, String reconToken){
		if(accountId == null) return false;
		
		HashMap<String,LastLoginInfo> players = null;
		LastLoginInfo info = null;
		
		if(!accountLoginRecordMap.containsKey(accountId)){
			players = new HashMap<String,LastLoginInfo>();
			info = new LastLoginInfo();
			players.put(reconToken, info);
			accountLoginRecordMap.put(accountId, players);
		}else if(!accountLoginRecordMap.get(accountId).containsKey(reconToken)){
			info = new LastLoginInfo();
			accountLoginRecordMap.get(accountId).put(reconToken, info);
		}else
			info = accountLoginRecordMap.get(accountId).get(reconToken);
		
		info.lastLoginPlayerGuid = lastLoginPlayerGuid;
		info.lastOfflineTime = -1;
		return true;
	}

	public boolean updateAccountLastLoginInfo(GUID accountId, String passwordCode, GUID sessionId,
			GUID lastLoginPlayerGuid, String lastRandomToken, String beforeToken) {
		if (accountId == null)
			return false;
		
		HashMap<String,LastLoginInfo> players = null;
		LastLoginInfo info = null;
		
		if (!accountLoginRecordMap.containsKey(accountId)) {
			//沒有創新資料給他
			players = new HashMap<String,LastLoginInfo>();
			info = new LastLoginInfo();
			players.put(lastRandomToken, info);
			accountLoginRecordMap.put(accountId, players);
		} else if(!accountLoginRecordMap.get(accountId).containsKey(lastRandomToken)){
			//沒有創新資料給他
			info = new LastLoginInfo();
			accountLoginRecordMap.get(accountId).put(lastRandomToken, info);
		} else
			info = accountLoginRecordMap.get(accountId).get(lastRandomToken);
		
		// 將目前 session id 跟 lastLoginInfo 關聯起來
		sessionToLastLoginInfoMap.put(sessionId, info);

		//刪去之前的token資料
		if (beforeToken != null) {
			accountLoginRecordMap.get(accountId).remove(beforeToken);
		}
		
		if (passwordCode != null) {
			lastCodeToAccountMap.put(passwordCode, accountId);
		}
		info.verifyCode = passwordCode;
		info.lastLoginPlayerGuid = lastLoginPlayerGuid;
		info.lastRandomToken = lastRandomToken;

		info.lastOfflineTime = -1;
		return true;
	}

	/**
	 * 更新離線時間, 過期要從離線多久開始算
	 * @param accountId
	 * @return
	 */
	public boolean updateAccountLastOfflineTime(GUID accountId, String reconToken){
		if(accountId == null) return false;
		LastLoginInfo info = null;
		if(!accountLoginRecordMap.containsKey(accountId) || !accountLoginRecordMap.get(accountId).containsKey(reconToken)){
			return false;
		}
		else
			info = accountLoginRecordMap.get(accountId).get(reconToken);
		
		info.lastOfflineTime = System.currentTimeMillis();
		return true;
	}
	
	public void onPlayerDisconnect(SSessionCloseNotify notify) {
		if (notify == null) {
			return;
		}

		// 更新這個 session 對應的登入資訊離線時間
		if (notify.getSessionId() != null) {
			if (sessionToLastLoginInfoMap.containsKey(notify.getSessionId())) {
				LastLoginInfo info = sessionToLastLoginInfoMap.get(notify.getSessionId());
				info.lastOfflineTime = System.currentTimeMillis();
		
				// 更新完就可以把資料刪掉
				sessionToLastLoginInfoMap.remove(notify.getSessionId());
			}
		}
	}
}
class LastLoginInfo{
	/**
	 * 上一次的gateway認證碼
	 */
	public String verifyCode;
	/**
	 * 上一次登入玩家的guid
	 */
	public GUID lastLoginPlayerGuid;
	/**
	 * 上一次登入取得的隨機Token
	 */
	public String lastRandomToken;
	/**
	 * 上一次離線時間, TODO 用來做expire檢查
	 */
	public long lastOfflineTime;
}
